package com.geek.auth.service;

import com.geek.auth.domain.AuthToken;
import com.geek.auth.dao.CredentialStorage;
import com.geek.auth.dao.MysqlCredentialStorage;

import java.util.*;
import java.util.stream.Collectors;

public class DefaultApiAuthenticatorImpl implements ApiAuthenticator {
    private static final Collection<String> REQUIRE_PARAMS = Arrays.asList("appId", "bizContent", "token", "timestamp");
    private CredentialStorage credentialStorage;

    public DefaultApiAuthenticatorImpl() {
        this.credentialStorage = new MysqlCredentialStorage();
    }

    public DefaultApiAuthenticatorImpl(CredentialStorage credentialStorage) {
        this.credentialStorage = credentialStorage;
    }

    @Override
    public void auth(String text) {
        auth(parseText(text));
        System.out.println("auth pass");
    }

    /**
     * 将参数转为map
     * @param text
     * @return
     */
    private Map<String, String> parseText(String text) {
        Map<String, String> result = new HashMap<>();

        StringBuilder sb = new StringBuilder();
        String key = null;
        char[] chars = text.toCharArray();
        int i = 0;

        while (i < chars.length) {
            char c = chars[i];

            switch (c) {
                case '=':
                    key = sb.toString();
                    sb = new StringBuilder();
                    break;
                case '&':
                    result.put(key, sb.toString());
                    key = null;
                    sb = new StringBuilder();
                    break;
                default:
                    sb.append(c);
            }
            i++;
        }

        if (key != null) {
            result.put(key, sb.toString());
        }
        return result;
    }

    @Override
    public void auth(Map<String, String> params) {
        List<String> collect = REQUIRE_PARAMS.stream().filter(s -> !params.containsKey(s)).collect(Collectors.toList());
        if (!collect.isEmpty()) {
            throw new RuntimeException("必要参数缺失：" + collect);
        }

        AuthToken clientAuthToken = new AuthToken(Long.parseLong(params.get("timestamp")), params.get("token"));
        if (clientAuthToken.isExpired()) {
            throw new RuntimeException("Token is expired.");
        }

        String password = credentialStorage.getAppSecretByAppId(params.get("appId"));
        AuthToken serverAuthToken = AuthToken.generate(params, password);
        if (!serverAuthToken.match(clientAuthToken)) {
            throw new RuntimeException("Token verfication failed.");
        }
    }
}